﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;

namespace FloatToBinary
{
    public class FloatValue
    {
        #region Fields
        public string InitValue { get; set; }
        private int _even;
        private float _decimal;
        private string _evenBinary;
        private string _decimalBinary;
        public string Sign { get; private set; }
        public string Exponent { get; private set; }
        public string Mantissa { get; private set; }
        public string InvertedBinaryToFloat { get; private set; }

        #endregion

        #region Constructors
        public FloatValue(string initValue)
        {
            this.InitValue = initValue;
            this._decimal = 0;
            this.ParceToEvenAndDecimalParts();
            this._decimalBinary = ParseDecimalPartToBinary(this._decimal);
            this._evenBinary = ParseIntToBinary(Math.Abs(this._even));
            this.Sign = GetSignInBinaryFormat();
            string[] exponentAndMantissa = GetExponentAndMantissaInBinaryFormat();
            this.Exponent = exponentAndMantissa[0];
            this.Mantissa = exponentAndMantissa[1];
            this.InvertedBinaryToFloat = (this.Sign == "1") ? "-" + InvertToFloat() : "+" + InvertToFloat();
        }

        private string InvertToFloat()
        {
            int exponent=Convert.ToInt32(this.Exponent,2)-127;
            string complementedMantissa = "1" + this.Mantissa;
            double invertedValue = 0;
            for (int i = 0; i < 25; i++)
            {
                int baseZeroOrOne = Convert.ToInt32(complementedMantissa.Substring(i,1));
                invertedValue += (baseZeroOrOne * Math.Pow(2, exponent - i));
            }
            return invertedValue.ToString();
        }

        #endregion

        private void ParceToEvenAndDecimalParts()
        {

            string[] initToString = InitValue.Split(DecimalSeparator.Separator);
            _even = int.TryParse(initToString[0], out _even) ? int.Parse(initToString[0]) : 0;
            if (initToString.Length != 1)
            {
                initToString[1] = "0" + DecimalSeparator.Separator + initToString[1];
                this._decimal = float.Parse(initToString[1]);
            }
        }

        public string GetSignInBinaryFormat()
        {
            if (Convert.ToDouble(InitValue) >= 0)
                return "0";
            else
                return "1";
        }

        public string[] GetExponentAndMantissaInBinaryFormat()
        {
            int exponentInt = GetExponent();
            string exponentBinary = ParseIntToBinary(exponentInt+127).Substring(24, 8);
            string mantissaBinaryFull = this._evenBinary + this._decimalBinary;
            string mantissaBinary = mantissaBinaryFull.Substring(mantissaBinaryFull.IndexOf('1') + 1, 24);
            return new[] { exponentBinary, mantissaBinary };
        }

        private string ParseIntToBinary(int value)
        {
            #region Previous decision
            /*StringBuilder temp=new StringBuilder();
            if (value==0)
            {
                temp.Append(0);
            }
            while (value!=0)
            {
                temp.Append(value%2);
                value /= 2;
            }           
            char[] outSequence = new char[temp.ToString().ToCharArray().Length];
            int j = 0;
            for (int i = temp.ToString().ToCharArray().Length - 1; i >= 0;i-- )
            {
                outSequence[j] = temp.ToString().ToCharArray()[i];
                j++;
            }*/

            #endregion
            string initialBinary = Convert.ToString(value, 2);
            StringBuilder outBinary=new StringBuilder(initialBinary);
            int initialLength = outBinary.Length;
            outBinary.Insert(0, new string('0', 32 - initialLength));          
            return outBinary.ToString();
        }

        private string ParseDecimalPartToBinary(float value)
        {
            StringBuilder tempString = new StringBuilder();
            float tempFloat = value;
            while ((tempString.Length < 48))
            {
                tempFloat *= 2;
                if (tempFloat == 1)
                {
                    tempString.Append("1");
                    tempFloat = 0;
                }
                if (tempFloat >= 1)
                {
                    tempString.Append("1");
                    tempFloat -= 1;
                }
                else
                {
                    tempString.Append("0");
                }

            }

            return tempString.ToString();
        }

        public int GetExponent()
        {

            if (_even == 0)
            {
                return -(this._decimalBinary.IndexOf('1') + 1);

            }
            else
            {
                return 32-(this._evenBinary.IndexOf('1') + 1);
            }
        }
    }
}